﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics.Contracts;

namespace SimpleIR
{
	/// <summary>
	/// Represents a single member field object.
	/// </summary>
	public sealed class IRMemberField : IRCompareableName
	{
		private readonly SpecialFieldTag m_sff;
		private readonly FieldQualifiers m_fqual;
		
		private readonly IRType m_defInClass;
		private readonly String m_fname;
		private readonly IRType m_ftype;

		[ContractInvariantMethod]
		private void ObjectInvariant()
		{ 
			Contract.Invariant(this.m_defInClass != null);
			Contract.Invariant(!String.IsNullOrEmpty(this.m_fname));
			Contract.Invariant(this.m_ftype != null);
			Contract.Invariant(!(this.m_ftype is IRReferenceType), "These should only be used for locals.");
		}

		internal IRMemberField(IRType defClass, String name, IRType fieldType, SpecialFieldTag spf, FieldQualifiers qual)
			: base()
		{
			Contract.Requires(defClass != null);
			Contract.Requires(name != null);
			Contract.Requires(fieldType != null);
			Contract.Requires(!(fieldType is IRReferenceType), "These should only be used for locals.");

			this.m_sff = spf;
			this.m_fqual = qual;

			this.m_defInClass = defClass;
			this.m_fname = name;
			this.m_ftype = fieldType;
		}

		/// <summary>
		/// Return the class type where this field is defined.
		/// </summary>
		public IRType DefinedInClass 
		{ 
			get 
			{
				Contract.Ensures(Contract.Result<IRType>() != null);

				return this.m_defInClass; 
			} 
		}

		/// <summary>
		/// Return the type that is stored in this field.
		/// </summary>
		public IRType FieldType 
		{ 
			get 
			{
				Contract.Ensures(Contract.Result<IRType>() != null);

				return this.m_ftype; 
			} 
		}

		/// <summary>
		/// Return the unqualified name of this field.
		/// </summary>
		public String FieldName 
		{ 
			get 
			{
				Contract.Ensures(Contract.Result<String>() != null);

				return this.m_fname; 
			} 
		}

		/// <summary>
		/// Get the field qualifier tag for this field.
		/// </summary>
		public FieldQualifiers FieldQualifier
		{ get { return this.m_fqual; } }

		/// <summary>
		/// True if this is a container contents field.
		/// </summary>
		public bool IsSummaryField
		{ get { return this.m_sff == SpecialFieldTag.SummaryLocationField; } }

		/// <summary>
		/// True if this is a container cardinality field.
		/// </summary>
		public bool IsContinerCardField
		{ get { return this.m_sff == SpecialFieldTag.ContainerCardField; } }

		/// <summary>
		/// True if this is the field in an enumerator that points to the field which is being enumerated over.
		/// </summary>
		public bool IsEnumeratorContainerTargetField
		{ get { return this.m_sff == SpecialFieldTag.EnumeratorCollectionField; } }

		public override String ToString()
		{ return this.m_defInClass.ToString() + "@" + this.m_fname; }
	}
}
